from django.shortcuts import render
from django.shortcuts import redirect,reverse,get_object_or_404,HttpResponse
from django.http import StreamingHttpResponse
from django.contrib import messages
from Method_Decorate import Decoration
from file_manage import models
from file_manage import forms
from file_manage import handles
from Method_Decorate import Decoration,Yaml_action
import os
import time
import datetime
import re
# ##############随程序启动调度器
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.executors.pool import ThreadPoolExecutor
from django_apscheduler.jobstores import DjangoJobStore

jobstores = {
    'default': DjangoJobStore()
}
executors = {
    'default': ThreadPoolExecutor(20)
}
job_defaults = {
    'max_instance': 4,
}
scheduler = BackgroundScheduler(jobstores=jobstores,
                                     executors=executors,
                                     job_defaults=job_defaults,
                                     timezone='Asia/Shanghai')
scheduler.start()
###################
# from manage import scheduler_task    #用于写任务调度器
# from Method_Decorate.Time_task import scheduler_task
#在目录界面会显示目录和文件的<a>标签  此标签链接获取途径为file和directory的get_url方法，通过点进这个方法进入detail
#点击文件<a>标签的时候 会进入到detail视图  detail将model变量传入到index.html之中！
#点击文件夹<a>标签同理
#extra_filters用于 「文件」： / versirity / xxx  这一行的显示

# Create your views here.


@Decoration.check_login
def index(request):
    """
    桌面视图
    """
    user_database=models.User.objects.get(name=request.session["user_id"]) #查出登录用户的账号状态 注意此时有两个条件符合时会出现异常
    form_upload=forms.UploadForm()
    try:
        #表中有多个属于user_database的文件夹   只取第一个即可   要将文件路径删除
        directory_database=user_database.directory_set.filter(owner=user_database.pk)[0]
    except IndexError:
        #如果没有则直接创建一个属于它的文件夹
        directory_database=models.Directory.create_root_dir(user_database)
    request.session['directory']=directory_database.pk
    context={"username":request.session["user_id"],'user':user_database,'form':form_upload,'directory':directory_database,}
    return render(request, 'login/index.html',context)


def login(request):
    """
    登录视图
    :param request:
    :return:
    """
    if request.session.get('is_login',False):  #判断是否有is_login  没有则返回None
        return redirect(reverse('generate_yaml:small_gener'))
    if request.method == 'POST':
        login_form = forms.UserForm(request.POST)
        tmp = {'login_form':login_form}
        tmp["message"] = '请检查填写的内容！'
        try:
            if login_form.is_valid() :
                username = login_form.cleaned_data.get('username')          #表单获取
                password = login_form.cleaned_data.get('password')          #表单获取
                user_database=models.User.objects.get(name=username)           #数据库数据
                if user_database.password==password:  #密码正确
                    request.session['is_login'] = True
                    #session存储的id和name号
                    request.session['user_id'] = username
                    request.session['user_name'] =  password
                    return redirect(reverse('file_manage:index'))
                else:                               #密码错误
                    tmp["message"] = '密码不正确！'
                    return render(request, 'login/login.html',  tmp)
        except models.User.DoesNotExist:  # 不检查存在多个结果的情况，注册(或者admin内)就不允许重复用户名
            #数据效验失败 (用户不存在）
            tmp["message"] = '用户不存在！'
            return render(request, 'login/login.html', tmp)
    else:  # GET情况下
        login_form = forms.UserForm()
        context={'login_form':login_form}
        return render(request, 'login/login.html', context)





def register(request):
    pass
    return render(request, 'login/register.html')


def logout(request):
    if not request.session.get('is_login', None):
        return redirect(reverse("file_manage:Login"))

    request.session.flush()
    # del request.session['is_login']
    return redirect(reverse("file_manage:Login"))

# @Decoration.check_login
def upload(request):
    """
    上传视图
    :param request:
    :return:
    """
    if request.method == 'POST':
        user_database=models.User.objects.get(name= request.session['user_id'])
        #此时文件夹的位置
        dir_pk = request.session['directory']
        #当前文件夹的模型
        directory = models.Directory.objects.get(pk=dir_pk)

        form = forms.UploadForm(request.POST, request.FILES)
        if form.is_valid():
            files = request.FILES.getlist('files')
            up_flag=handles.handle_uploaded_files(files, user_database, directory,request)  #user_database\directory 都是为models类型
            if not up_flag:
                return redirect('file_manage:index')
            # return redirect(reverse('file_manage:detail', username=user_database.name, path=directory.path))
            if directory.path:
                turn_to=reverse('file_manage:detail',
                                kwargs={"username":str(user_database.name),"path":str(directory.path).replace("/","_=_"),})
            else:
                turn_to = reverse('file_manage:detail',
                                  kwargs={"username": str(user_database.name),})
            return redirect(turn_to)
    return redirect('file_manage:index')


@Decoration.check_login
def detail(request, username, path=''):
    """
        目录或者文件的详情页
        用户名和路径足以确定唯一的文件或者目录，不需要 pk
        而且 URL 中放 pk 不太美观
        注意区别：
            File.path 不含文件名
            detail(path) 包含了文件名，因为是 URL
    """
    if path:
        path=path.replace("_=_","/")
    user = get_object_or_404(models.User, name=username)
    file = models.File.objects.filter(owner=user, path=os.path.dirname(path), name=os.path.basename(path))
    directory = models.Directory.objects.filter(owner=user, path=path)
    form = forms.UploadForm()
    context={}

    if file and file.count() == 1:
        file = file[0]
        context = {'username': user.name, 'file': file, 'is_file': True}
    elif directory and directory.count() >= 1:  #12,14改
        directory = directory[0]
        request.session['directory']=directory.pk
        context = {'username': user.name, 'form': form, 'directory': directory, 'is_file': False}
    elif directory.count() == 0:  # 主目录被删了，自动新建
        directory = models.Directory.create_root_dir(user)
        context = {'username': user.name, 'form': form, 'directory': directory, 'is_file': False}
    else:
        import pdb
        pdb.set_trace()
        # raise Http404

    return render(request, 'login/index.html', context)

#*********
#操作
##########
@Decoration.check_login
def move(request,pk):
    """
    移动文件到另一个文件夹
    :param request:
    :param pk:
    :return:
    """
    #pk文件
    file_database=get_object_or_404(models.File,pk=pk)
    user_database=models.User.objects.get(name=request.session['user_id'])
    #当前用户所有文件夹
    directory_database=models.Directory.objects.filter(owner=user_database)
    if request.method=="POST":
        try:
            directory_pk=request.POST['optionsRadios']
            to_directory=models.Directory.objects.get(pk=directory_pk)
            file_database.parent=to_directory
            file_database.path=to_directory.path
            file_database.save()
            return redirect(reverse("file_manage:index"))
        except Exception as e:
            messages.error(request,"没有选择相关文件夹！")
            return render(request,"login/move.html",{"directory":directory_database,"file":file_database})

    else:#get的情况下
        return render(request,"login/move.html",{"directory":directory_database,"file":file_database})

@Decoration.check_login
def delete(request, pk):
    """ 删除文件！提供一个页面，让用户确认 """
    file = get_object_or_404(models.File, pk=pk)
    directory = file.parent
    if request.method == 'POST':    #用户做出选择时
        form = forms.ConfirmForm(request.POST)
        if form.is_valid():
            confirm = form.cleaned_data['confirm']
            if confirm == 'y':
                models.Link.minus_one(file) # 里面包含了删除动作
                try:
                    scheduler.remove_job(handles.task_condition(pk))
                except BaseException:
                    print("该文件无定时任务")
                return redirect(directory.get_url())
            else:
                return redirect(directory.get_url())
    form = forms.ConfirmForm()
    return render(request, 'login/confirm.html', {'file': file, 'form': form, 'is_file': True})

@Decoration.check_login
def rmdir(request, pk):
    """ 删除目录和下面的文件、子目录 """
    directory = get_object_or_404(models.Directory, pk=pk)
    parent = directory.parent

    if request.method == 'GET':
        form = forms.ConfirmForm()
        context = {
            'directory': directory,
            'form': form,
            'is_file': False,
        }
        return render(request, 'login/confirm.html', context)

    elif request.method == 'POST':
        form = forms.ConfirmForm(request.POST)
        if form.is_valid():
            confirm = form.cleaned_data['confirm']
            if confirm == 'y':
                directory.rmdir()
                if parent:
                    return redirect(parent.get_url())
                else: # parent 是空，说明用户删除了整个家目录，那么回首页并创建一个空的家目录
                    return redirect(reverse("file_manage:index"))
            else:
                return redirect(directory.get_url())

@Decoration.check_login
def mkdir(request, pk):
    """
        创建目录
    """

    current_dir = models.Directory.objects.get(pk=pk)

    # user = request.user
    user_database = models.User.objects.get(name= request.session['user_id'] )
    if request.method == 'GET':
        form = forms.CreateDirectoryForm()

    else:# request.method == 'POST'
        form = forms.CreateDirectoryForm(request.POST)
        if form.is_valid():
            name = form.cleaned_data['name']
            new_dir = models.Directory.objects.create(
                name = name,
                owner = user_database,
                parent = current_dir,
                path = os.path.join(current_dir.path, name),
            )
            # 作为 url 参数的时候，去掉最开头的 '/' ，以免变成 username//test 难看
            return redirect('file_manage:detail', username=user_database.name, path=new_dir.path.replace("/","_=_")) #url不允许出现“/”
    return render(request, 'login/mkdir.html', {'form': form, 'directory': current_dir})

@Decoration.check_login
def edit(request, pk):
    """
    重命名视图：
    暂时只支持编辑文件名
    """

    file = get_object_or_404(models.File, pk=pk)
    user_database = models.User.objects.get(name= request.session['user_id'] )
    if request.method == 'GET':
        form = forms.EditForm({'name': file.name})
    else:
        form = forms.EditForm(request.POST)
        if form.is_valid():
            name = form.cleaned_data['name']
            file.name = name
            file.save()
            path = os.path.join(file.path, file.name)
            return redirect('file_manage:detail', username=user_database.name, path=path.replace("/","_=_"))
    context = {'form': form, 'file': file}
    return render(request, 'login/edit.html', context)

@Decoration.check_login
def download(request, pk):
    """ 一般是下载，当附带 preview=True query string 时为预览 """
    file = get_object_or_404(models.File, pk=pk)
    tmp_path=handles.get_file_path(file)
    def file_iterator(file_path, chunk_size=512):
        """必须为rb 二进制流"""
        with open(file_path,'rb') as f:
            while True:
                c = f.read(chunk_size)
                if c:
                    yield c
                else:
                    break
    # if request.GET.get('preview'):
    #     filetype = mimetypes.guess_type(file.name)[0]
    #     if not filetype:
    #        filetype = 'application/octet-stream'
    #     response['Content-Type'] = filetype
    # else:
    #     response['Content-Type'] = 'application/force-download'
    #     response['Content-Disposition'] = 'attachment; filename={0}'.format(file_name)
    file_name = os.path.basename(tmp_path)
    response = StreamingHttpResponse(file_iterator(tmp_path))
    response['Content-Type'] = 'application/octet-stream'
    response['Content-Disposition'] = 'attachment;filename={0}'.format(file_name)
    return response

from generate_yaml.views import file_folder,report_folder
@Decoration.check_login
def to_gen_process(request,pk):
    """
    从file_manage这一页进行最后的测试
    进行最后一步测试
    :param request:
    :param pk: 文件主键
    :return:
    """
    file = get_object_or_404(models.File, pk=pk)
    directory = file.parent
    # handles.task_condition(pk)   #验证
    if request.method == 'POST':  # 用户做出选择时或者该任务为定时任务时
        form = forms.Confirm_Html_Form(request.POST)
        if form.is_valid():
            confirm = form.cleaned_data['confirm']
            app_path= form.cleaned_data['search_T']
            app_database=models.App.objects.get(app_path=app_path)
            if app_database.judge_condition_compile():
                messages.error(request,"正在编译！无法使用")
            else:
                if confirm == 'y':  #进行对应的操作
                    # models.Link.minus_one(file)  # 里面包含了删除动作
                    path=handles.get_file_path(file)
                    request.session['tmp_time'] = time.strftime("%Y-%m-%d_%H_%M_%S")
                    request.session['base_path'] = os.path.abspath(
                        (os.path.join(os.getcwd(), "..")) + file_folder + report_folder)
                    request.session['main_process'] = {}
                    request.session['main_process']['app_path']=app_path
                    request.session['main_process']['report_path']=request.session['base_path']+"/"+request.session['tmp_time']
                    request.session['main_process']['Total_case_path']=path
                    request.session['main_process']['total_pk'] = pk
                    # turn_to=reverse("generate_yaml:progress_bar_html")
                    # return redirect(turn_to)
                    return render(request, "process/progress_bar.html")
                    # return redirect(directory.get_url())
                else:
                    return redirect(directory.get_url())
    form = forms.Confirm_Html_Form()
    return render(request, 'login/confirm_condition.html', {'file': file, 'form': form, 'condition_action': "gen_html_process"})

@Decoration.check_login
def setting(request):
    """
    设置，目前只弄了邮箱选定
    :param request:
    :return:
    """
    username = request.session['user_id']
    user_database = models.User.objects.get(name=username)
    if request.method=="POST":
        if request.POST.get('on_off_button')=='on':
            user_database.email_condition=True
        else:
            user_database.email_condition=False
        user_database.save()
        return redirect(reverse("file_manage:index"))
    else:
        return render(request,'login/setting.html',{"user":user_database})

@Decoration.check_login
def timing_task(request,pk):
    """
    某个文件进行定时任务
    :param request:
    :param pk: 文件主键号码
    :return:
    """
    file_database = get_object_or_404(models.File, pk=pk)
    form = forms.Confirm_Html_Form()
    directory_database=file_database.parent
    if request.method=="POST":
        form = forms.Confirm_Html_Form(request.POST)
        if form.is_valid():
            confirm = form.cleaned_data['confirm']
            app_path = form.cleaned_data['search_T']
            time_scope=request.POST['time_set'].split(" - ")  #可能会出现只选择一个时间的情况需要判定
            # interval_time_list=request.POST['interval_time'].split("-")
            interval_time_pattern=re.compile(r'([0-9]{0,4})-([0-9]{0,4})-([0-9]{0,4})')
            interval_time_group=interval_time_pattern.findall(request.POST['interval_time'])
            if not interval_time_group:
                messages.error(request,"输入的间隔时间无法识别！")
                return redirect(directory_database.get_url())
            interval_time_hours=int(interval_time_group[0][0])*7*24+int(interval_time_group[0][1])*24+int(interval_time_group[0][2])*1
            if(len(time_scope)>=2):
                set_start_time=time_scope[0]
                set_end_time=time_scope[1]
                minimum_time=(datetime.datetime.now()+datetime.timedelta(minutes=10)).strftime("%Y-%m-%d %H:%M:%S")#设定的最小时间
                file_database.app_path = app_path
                file_database.save()
                if confirm == 'y':
                    if set_start_time<minimum_time:  #时间间隔不得小于十分钟
                    # if False:
                        messages.error(request,"时间不符要求！")
                    elif interval_time_hours==0:
                        scheduler.add_job(handles.time_middlesite_task,
                                                 args=[pk,request.session['user_id'],],
                                                 trigger='date',
                                                 id=datetime.datetime.now().strftime("%Y_%m_%d_%H-%M-%S"),
                                                 run_date=set_start_time,)
                    elif interval_time_hours!=0:
                        scheduler.add_job(handles.time_middlesite_task,
                                          args=[pk, request.session['user_id'], ],
                                          trigger='interval',
                                          id=datetime.datetime.now().strftime("%Y_%m_%d_%H-%M-%S"),
                                          start_date=set_start_time,
                                          end_date=set_end_time,
                                          hours=interval_time_hours,)
                        a=5

            # else:#confirm != 'y'
            return redirect(directory_database.get_url())
    else:
        pass
    return render(request, 'login/confirm_condition.html',
                 {'file': file_database, 'form': form, 'condition_action': "timed_task"})



@Decoration.check_login
def timing_task_view(request):
    """
    记录某个用户目前的定时任务总览
    :param request:
    :return:
    """
    task_list=[]
    file_name_list=[]
    for find_tmp in scheduler.get_jobs():
        if find_tmp.args[1]==request.session["user_id"] and 'time_middlesite_task' in find_tmp.name:
            task_list.append(find_tmp)
            file_name_list.append(models.File.objects.get(pk=find_tmp.args[0]))
    return render(request,'login/timing_task_view.html',
                  # {"jobs_list":task_list,
                  #  "file_list":file_name_list,
                  { "zip_data":zip(task_list,file_name_list),
                   "username":request.session["user_id"],})


@Decoration.check_login
def bind_mail(request,pk):
    """
    给文件绑定邮箱
    :param request:
    :param pk: 文件编号
    :return:
    """
    user_database=models.User.objects.get(name=request.session['user_id'])
    file_database=models.File.objects.get(pk=pk)
    Email_group_database=models.Email_group.objects.all()
    user_email_database=user_database.email_data.all()
    file_email_database=file_database.email_data.all()
    if request.method=="POST":
        # pass

        for tmp_email in user_email_database:
            try:
                if request.POST[tmp_email.email_address]:  #先判断在不在
                    if tmp_email not in file_email_database:
                        file_database.email_data.add(tmp_email)  # 加入该文件
                        file_database.save()
            except Exception as e:
                if tmp_email in file_email_database:  #不在则看在不在数据库中
                    file_database.email_data.remove(tmp_email)
                    file_database.save()
        return redirect(file_database.get_url())
        # return redirect()
    else:
        pass
    #需要手动刷新否则依旧读的是缓存的数据
    user_email_database=user_database.email_data.all()
    file_email_database=file_database.email_data.all()
    # file_email_database.

    return render(request,"login/bind_email.html",
                  {
                      "user_email_database":user_email_database,
                      "file_email_database":file_email_database,
                      "Email_group_database":Email_group_database,
                      # "user_database":user_database,
                      "file_database":file_database,
                  })

@Decoration.check_login
def remove_timing_task(request,id):
    """
    删除定时任务,点删除确定才会到这里来
    :param request:
    :param pk: 删除的任务的pk主键
    :return:
    """

    # scheduler.remove_job(handles.task_condition(pk))
    scheduler.remove_job(id)
    return redirect(reverse("file_manage:view_for_timing_task"))


def preview(request,pk):
    """
    preview预览当前文件属性（只预览yaml）
    :param request:
    :param pk:文件主键
    :return:
    """
    #返回404是没有该数据
    file_database=get_object_or_404(models.File,pk=pk)
    file_name=file_database.name
    file_path=file_database.get_full_path_file()
    num_count=1
    if file_name.split(".")[-1]=="yaml":
        small_path_list=Yaml_action.casecollection_action.read_small_case_path(file_path)
        iter_tmp=map(Yaml_action.case_action.read_search_path,small_path_list)#获取的是迭代器
        response='<h3>文件路径:</h3>'
        for tmp in iter_tmp:
            if tmp!=False:
                response+="<p>小用例路径:{0}</p>".format(tmp)
        return HttpResponse(response)

    else:
        return HttpResponse('<p>非用例文件不能预览</p>')



